using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Diagnostics;
using DataTreeLib;
using System.Collections;
using DocToolTipLib.Dialogs;
using DocToolTipLib.Enums;
using DocToolTipLib.Properties;
using DocToolTipLib.DTree;
using DocToolTipLib.Controls;
using DocToolTipLib.Mappers;


namespace DocToolTipLib
{
  public partial class FrmDocManager : Form
  {
    #region Attributes

    private List<Control> _lstControls;
    private List<DocToolTip> _lstDocToolTips;
    private DTreeNode<DocToolTip> _rootDocToolTipNode;
    private TypeFilterTNode _rootTypeFilterTreeNode;
    private TreeViewController<DocToolTip> _treeViewController;
    private TreeViewController<TypeFilter> _typeFilterTVController;
    private Dictionary<Type, TypeFilter> _dicFilteredTypes;
    private Dictionary<Type, TypeFilterTNode> _dicTypeFilterTreeNode;
    #endregion Attributes

    #region Constructor
    public FrmDocManager()
    {
      InitializeComponent();
      InitializeComponentEx();
      _lstDocToolTips = new List<DocToolTip>();
      _dicFilteredTypes = new Dictionary<Type, TypeFilter>();
      _dicTypeFilterTreeNode = new Dictionary<Type, TypeFilterTNode>();
      _lstControls = new List<Control>();
      loadImages();
    }


    private void loadImages()
    {
      string[] controlNames = new string[]
        {
          "Control_ActiveDocumentHost",
          "Control_BackgroundWorker",
          "Control_Button",
          "Control_Checkbox",
          "Control_CheckedListBox",
          "Control_ColorDialog",
          "Control_ComboBox",
          "Control_ContextMenu",
          "Control_ContextMenuStrip",
          "Control_DataConnector",
          "Control_DataGrid",
          "Control_DataGridView",
          "Control_DataNavigator",
          "Control_DateTimePicker",
          "Control_DomainUpDown",
          "Control_ErrorProvider",
          "Control_FlowLayoutPanel",
          "Control_FolderBrowserDialog",
          "Control_FontDialog",
          "Control_Form",
          "Control_GroupBox",
          "Control_HelpProvider",
          "Control_HScrollBar",
          "Control_ImageList",
          "Control_Label",
          "Control_LinkLabel",
          "Control_ListBox",
          "Control_ListView",
          "Control_MainMenu",
          "Control_MaskedTextBox",
          "Control_MenuStrip",
          "Control_MonthCalendar",
          "Control_NotifyIcon",
          "Control_NumericUpDown",
          "Control_OpenFileDialog",
          "Control_PageSetupDialog",
          "Control_Panel",
          "Control_PictureBox",
          "Control_PrintDialog",
          "Control_PrintDocument",
          "Control_PrintPreviewControl",
          "Control_PrintPreviewDialog",
          "Control_ProgressBar",
          "Control_RadioButton",
          "Control_RichTextBox",
          "Control_SaveFileDialog",
          "Control_Sound",
          "Control_SplitContainer",
          "Control_Splitter",
          "Control_StatusBar",
          "Control_StatusStrip",
          "Control_TabControl",
          "Control_TableLayoutPanel",
          "Control_TextBox",
          "Control_Timer",
          "Control_ToolBar",
          "Control_ToolStrip",
          "Control_ToolTip",
          "Control_TrackBar",
          "Control_TreeView",
          "Control_VScrollBar",
          "Control_WebBrowser",
        };

      foreach (string strControlName in controlNames)
      {
        Bitmap bmp = Resources.ResourceManager.GetObject(strControlName) as Bitmap;
        _controlImageList.Images.Add(strControlName, bmp);
      }
    }

    private void InitializeComponentEx()
    {
      
    }

    private DTreeNode<DocToolTip> createDTreeNodeDocToolTip(Control control, DTreeNode<DocToolTip> parent)
    {
      DTreeNode<DocToolTip> dTNode = createDNode(control);
      parent.Nodes.Add(dTNode);
      _lstDocToolTips.Add(dTNode.Value);
      DocToolTip toolTip = dTNode.Value;
      dTNode.Value.ShowToolTip();
      dTNode.Value.RelativePositionType = EnumRelativePositionType.Top;

      addTypeFilter(control.GetType());
      addTypeFilterTNode(control.GetType());

      foreach (Control child in control.Controls)
      {
        DTreeNode<DocToolTip> dTTChild = createDTreeNodeDocToolTip(child, dTNode);
        toolTip.Children.Add(dTTChild.Value);
        
      }

      return dTNode;
    }

    DTreeNode<DocToolTip> createDNode(Control control)
    {
      DocToolTip toolTip = new DocToolTip(control, this);

      DTreeNode<DocToolTip> result = new DTreeNode<DocToolTip>(toolTip);
      return result;
    }

    //private DocToolTip createDocToolTips(Control control, TreeNodeCollection tNodeCollection)
    //{
    //  DocToolTip toolTip = new DocToolTip(control, this);
    //  TreeNode tNode = createTreeNode(toolTip);

    //  tNodeCollection.Add(tNode);
    //  _lstDocToolTips.Add(toolTip);

    //  foreach (Control child in control.Controls)
    //  {
    //    DocToolTip dTTChild = createDocToolTips(child, tNode.Nodes);
    //    toolTip.Children.Add(dTTChild);
    //  }
    //  return toolTip;
    //}

    //private TreeNode createTreeNode(DocToolTip toolTip)
    //{
    //  TreeNode tNode = new TreeNode(toolTip.Text);
    //  tNode.Tag = toolTip.Text;
    //  tNode.Text = toolTip.ControlName;
    //  tNode.Checked = toolTip.Visible;
    //  ImageList imageList = _treeView.ImageList;

    //  string strControlName = "Control_" + toolTip.ControlType.Name;
    //  int iIndex = -1;

    //  if (imageList.Images.ContainsKey(strControlName))
    //  {
    //    iIndex = imageList.Images.IndexOfKey(strControlName);
    //  }

    //  tNode.ImageIndex = iIndex;
    //  tNode.SelectedImageIndex = iIndex;
    //  return tNode;
    //}

    #endregion Contructor

    #region Properties
    private Control _mainControl;
    public Control MainControl
    {
      get { return _mainControl; }
      set
      {
        if (_mainControl != value)
        {
          deattach();
          _mainControl = value;
          if (_mainControl != null)
            attach(_mainControl);
        }
      }
    }
    #endregion Properties

    #region Document Outline - Event Handlers

    void _treeView_AfterSelNodesChanged(object sender, EventArgs e)
    {
      UpdatePropertyGrid();
    }

    #endregion Document Outline - Event Handlers



    private TypeFilterTNode addTypeFilterTNode(Type type)
    {
      TypeFilterTNode result = null;
      if (!_dicTypeFilterTreeNode.ContainsKey(type))
      {
        TypeFilterTNode parent = addTypeFilterTNode(type.BaseType);
        result = new TypeFilterTNode(type);
        _dicTypeFilterTreeNode.Add(type, result);
        parent.Nodes.Add(result);
      }
      else
      {
        result = _dicTypeFilterTreeNode[type];
      }
      return result;
    }

    private void addTypeFilter(Type type)
    {
      if (type != typeof(object))
      {
        if (!_dicFilteredTypes.ContainsKey(type))
        {
          _dicFilteredTypes.Add(type, new TypeFilter(type));
        }

        addTypeFilter(type.BaseType);
      }

    }

    private void deattach()
    {
      foreach (DocToolTip toolTip in _lstDocToolTips)
      {
        toolTip.Close();
      }

      _lstDocToolTips.Clear();
      _dicTypeFilterTreeNode.Clear();
      if (_rootDocToolTipNode != null)
      {
        _rootDocToolTipNode = null;
      }

      if (_rootTypeFilterTreeNode != null)
      {
        _rootTypeFilterTreeNode = null;
      }

      _treeView.Clear();
      _typeMapTreeView.Clear();
      _propertyGrid2.SelectedObjects = null;
    }

    private void attach(Control control)
    {
      _mainControl = control;

      _rootDocToolTipNode = new DTreeNode<DocToolTip>(null);
      _rootTypeFilterTreeNode = new TypeFilterTNode(typeof(object));
      _dicTypeFilterTreeNode.Add(typeof(object), _rootTypeFilterTreeNode);

      createDTreeNodeDocToolTip(_mainControl, _rootDocToolTipNode);

      string strMessage = _mainControl.GetType().ToString();
      _notifyIcon.ShowBalloonTip(3000, "DocToolTipHelper", strMessage, ToolTipIcon.Info);


      _typeFilterTVController = new TreeViewController<TypeFilter>(_typeMapTreeView,
                                                                  _rootTypeFilterTreeNode,
                                                                  new TypeFilterTNodeMapper());

      _treeViewController = new TreeViewController<DocToolTip>(_treeView, 
                                                              _rootDocToolTipNode,
                                                              new DocToolTipTreeNodeMapper());

    }

    #region NotifyIcon Events
    private void _notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
    {
      Show();
    }

    private void _notifyIcon_BalloonTipClicked(object sender, EventArgs e)
    {
      Show();
    }

    #endregion NotifyIcon Events


    private void FrmDocManager_FormClosing(object sender, FormClosingEventArgs e)
    {
      if (e.CloseReason == CloseReason.UserClosing)
      {
        e.Cancel = true;
        Hide();
      }

    }

    private void _treeView_AfterSelect(object sender, TreeViewEventArgs e)
    {
      UpdatePropertyGrid();
    }

    private void UpdatePropertyGrid()
    {
      ArrayList lstSelectedObjects = new ArrayList();
      foreach (TreeNode tNode in _treeView.SelectedNodes)
      {
        DTreeNode<DocToolTip> dTNode = _treeViewController.GetDataNode(tNode);
        DocToolTip docToolTip = dTNode.Value;
        if (docToolTip != null)
        {
          lstSelectedObjects.Add(docToolTip.ToolTipProperties);
        }
      }

      _propertyGrid2.SelectedObjects = lstSelectedObjects.ToArray();
    }



    private void _treeView_AfterCheck(object sender, TreeViewEventArgs e)
    {
      bool bChecked = e.Node.Checked;
      if ((e.Action == TreeViewAction.ByKeyboard) ||
        (e.Action == TreeViewAction.ByMouse))
      {
        
        
        if (_treeViewController != null)
        {
          if (_treeView.IsSelected(e.Node) || e.Node.IsSelected)
          {
            foreach (TreeNode tNode in _treeView.SelectedNodes)
            {
              DTreeNode<DocToolTip> dNode = _treeViewController.GetDataNode(tNode);
              dNode.Value.Visible = bChecked;
            }
          }
          else
          {
            _treeView.SelectedNode = e.Node;
            DTreeNode<DocToolTip> dNode = _treeViewController.GetDataNode(e.Node);
            dNode.Value.Visible = bChecked;

          }
          _treeViewController.UpdateAllNodes();
        }
      }
    }

    private void checkChildNode(TreeNode treeNode, bool bChecked)
    {
      foreach (TreeNode child in treeNode.Nodes)
      {
        child.Checked = bChecked;
        checkChildNode(child, bChecked);
      }
    }

    private void _btnHide_Click(object sender, EventArgs e)
    {
      Hide();
    }

    private void relocateToolStripMenuItem_Click(object sender, EventArgs e)
    {
      foreach (DocToolTip docToolTip in _lstDocToolTips)
      {
        docToolTip.Relocate();
      }
    }
    public override void Refresh()
    {
      base.Refresh();
      _treeView.Refresh();
      _treeViewController.UpdateAllNodes();
    }

    private void _propertyGrid2_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
    {
      Refresh();
    }


    private void setVisibleControlsByType(bool bVisible)
    {
      foreach (TreeNode tNode in _typeMapTreeView.SelectedNodes)
      {
        DTreeNode<TypeFilter> dNode = _typeFilterTVController.GetDataNode(tNode);

        foreach (DocToolTip tooltip in _lstDocToolTips)
        {
          if (tooltip.ControlType == dNode.Value.Type)
          {
            tooltip.Visible = bVisible;
          }
        }
      }
    }

    private void setVisibleChildrenControlsByType(bool bVisible)
    {
      foreach (TreeNode tNode in _typeMapTreeView.SelectedNodes)
      {
        DTreeNode<TypeFilter> dNode = _typeFilterTVController.GetDataNode(tNode);

        foreach (DocToolTip tooltip in _lstDocToolTips)
        {
          if (tooltip.ControlType == dNode.Value.Type)
          {
            tooltip.SetVisibleAllChildren(bVisible);
          }
        }
      }
    }

    private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
    {
      AboutBox dlg = new AboutBox();
      dlg.ShowDialog();
    }

    private void expandToolStripMenuItem_Click(object sender, EventArgs e)
    {
      ToolStripItem toolStripItem = sender as ToolStripItem;
      FacadeTreeView treeView = toolStripItem.Owner.Tag as FacadeTreeView;

      if (treeView.TreeNodeMouseDown != null)
      {
        treeView.TreeNodeMouseDown.ExpandAll();
      }
    }

    private void collapseToolStripMenuItem_Click(object sender, EventArgs e)
    {
      ToolStripItem toolStripItem = sender as ToolStripItem;
      FacadeTreeView treeView = toolStripItem.Owner.Tag as FacadeTreeView;

      if (treeView.TreeNodeMouseDown != null)
      {
        treeView.TreeNodeMouseDown.Collapse();
      }

    }

    private void _treeView_AfterSelNodeChanged(object sender, EventArgs e)
    {
      UpdatePropertyGrid();
    }

    private void _tsbtnExpand_Click(object sender, EventArgs e)
    {
      FacadeTreeView treeView = getActiveTreeView();
      foreach (TreeNode tNode in treeView.SelectedNodes)
      {
        tNode.ExpandAll();
      }
    }

    private FacadeTreeView getActiveTreeView()
    {
      FacadeTreeView treeView = null;
      if(_mainTabControl.SelectedIndex == 0)
      {
        treeView = _treeView;
      }
      else
      {
        treeView = _typeMapTreeView;
      }
      return treeView;
    }

    private void _tsbtnCollapse_Click(object sender, EventArgs e)
    {
      FacadeTreeView treeView = getActiveTreeView();
      foreach (TreeNode tNode in treeView.SelectedNodes)
      {
        tNode.Collapse();
      }
    }

    private void _tsbtnHide_Click(object sender, EventArgs e)
    {
      setVisibleControlsByType(false);
      Refresh();
    }

    private void _tsbtnShow_Click(object sender, EventArgs e)
    {
      setVisibleControlsByType(true);
      Refresh();
    }

    private void _tsbtnHideChildren_Click(object sender, EventArgs e)
    {
      setVisibleChildrenControlsByType(false);
      Refresh();
    }

    private void _tsbtnShowChildren_Click(object sender, EventArgs e)
    {
      setVisibleChildrenControlsByType(true);
      Refresh();

    }

    private void _tsbtnSelectChildren_Click(object sender, EventArgs e)
    {
      foreach (TreeNode tNode in _treeView.SelectedNodes)
      {
        _treeView.SelectAllNodes(tNode);
      }

      UpdatePropertyGrid();
    }

    private void clearAllToolStripMenuItem_Click(object sender, EventArgs e)
    {
      MainControl = null;

    }



    public void AddControl(Control control)
    {
      if(!_lstControls.Contains( control))
      {
        _lstControls.Add(control);
        populateListControlMenu();
      }
    }

    private void populateListControlMenu()
    {
      _controlListToolStripMenuItem.DropDownItems.Clear();
      if (_lstControls.Count > 0)
      {
        foreach (Control control in _lstControls)
        {
          ToolStripItem mnuItem = new ToolStripMenuItem(control.Name + ":" + control.GetType().Name);
          mnuItem.Tag = control;
          _controlListToolStripMenuItem.DropDownItems.Add(mnuItem);
        }
      }
      else
      {
        ToolStripItem mnuItem = new ToolStripMenuItem("Empty!");
        mnuItem.Enabled = false;
        _controlListToolStripMenuItem.DropDownItems.Add(mnuItem);
      }


    }

    public void RemoveControl(Control control)
    {
      if (_lstControls.Contains(control))
      {
        _lstControls.Remove(control);
        populateListControlMenu();
      }
    }

    private void _controlListToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)
    {
      if( e.ClickedItem.Tag != null)
      {
        MainControl = e.ClickedItem.Tag as Control;
      }
    }

  }
}